package com.singfan.core.service.impl;

import com.singfan.common.util.EncryptionUtil;
import com.singfan.common.util.StringUtil;
import com.singfan.core.dao.database.*;
import com.singfan.core.dao.database.model.*;
import com.singfan.core.dao.database.model.constant.*;
import com.singfan.core.dao.mongo.IBarberLocationDao;
import com.singfan.core.dao.mongo.IHairstyleLocationDao;
import com.singfan.core.service.BarberListResult;
import com.singfan.core.service.IBarberService;
import com.singfan.core.util.AccessTokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

/**
 * Author: hansonghe
 * Date: 2015-08-24 15:14
 * Desc:
 */
@Service
public class BarberServiceImpl implements IBarberService {
    @Autowired
    private IBarberDao barberDao;
    @Autowired
    private IBarberLocationDao barberLocationDao;
    @Autowired
    private IBarberHairstyleDao barberHairstyleDao;
    @Autowired
    private IHairstyleLocationDao hairstyleLocationDao;
    @Autowired
    private IBarberAppointmentDao barberAppointmentDao;
    @Autowired
    private IBarberTokenDao barberTokenDao;
    @Autowired
    private IPhoneSecurityCodeDao phoneSecurityCodeDao;
    @Autowired
    private IBarberCommentDao barberCommentDao;

    @Override
    public List<Barber> selectBarberListByShopId(long shopId, int serviceType, int dayTime, int clockTime) {
        List<Barber> result;
        List<Barber> barberList = barberDao.selectBarbersByShopId(shopId, serviceType);
        if (dayTime > 0 && clockTime > 0 && barberList.size() > 0){
            List<Long> barberIdList = new ArrayList<>(barberList.size());
            for (Barber barber : barberList){
                barberIdList.add(barber.getId());
            }
            List<Long> hasAppointmentList = barberAppointmentDao.barberHasAppointmentByDayClockTime(barberIdList, dayTime, clockTime);
            result = new ArrayList<>();
            for (Barber barber : barberList){
                if (!hasAppointmentList.contains(barber.getId())){
                    result.add(barber);
                }
            }
        }
        else {
            result = barberList;
        }

        return result;
    }

    @Override
    public BarberListResult findBarberList(int serviceType, int listOrderType, int cityId, int businessCircleId, double longitude, double latitude, int pageIndex, int pageSize, int dayTime, int clockTime, boolean onlyMaster) {
        BarberListResult barberListResult = new BarberListResult();
        List<Barber> barberList;
        int pIndex = pageIndex;
        int position = onlyMaster ? 3 : 0;
        if (listOrderType == FilterType.DISTANCE) {
            List<Long> barberIdList = new ArrayList<>();
            while (barberIdList.size() == 0){
                barberIdList = barberLocationDao.findBarberNearbyLocation(serviceType, cityId, businessCircleId, longitude, latitude, position, pIndex, pageSize);
                if (barberIdList.size() > 0){
                    pIndex++;
                    if (dayTime > 0 && clockTime > 0){
                        List<Long> hasAppointmentList = barberAppointmentDao.barberHasAppointmentByDayClockTime(barberIdList, dayTime, clockTime);
                        for (Long barberId : hasAppointmentList){
                            barberIdList.remove(barberId);
                        }
                    }
                }
                else {
                    break;
                }
            }

            barberList = barberDao.selectBarberList(barberIdList);
        }
        else {
            barberList = new ArrayList<>();
            while (barberList.size() == 0){
                List<Barber> tempBarberList = barberDao.selectBarberList(serviceType, listOrderType, cityId, businessCircleId, pIndex, pageSize, position);
                if (tempBarberList.size() > 0){
                    pIndex++;
                    if (dayTime > 0 && clockTime > 0){
                        List<Long> barberIdList = new ArrayList<>();
                        for (Barber barber : tempBarberList){
                            barberIdList.add(barber.getId());
                        }
                        List<Long> hasAppointmentList = barberAppointmentDao.barberHasAppointmentByDayClockTime(barberIdList, dayTime, clockTime);
                        for (Barber barber : tempBarberList){
                            if (!hasAppointmentList.contains(barber.getId())){
                                barberList.add(barber);
                            }
                        }
                    }
                    else {
                        barberList = tempBarberList;
                    }
                }
                else {
                    break;
                }
            }
        }

        barberListResult.setPageIndex(pIndex);
        barberListResult.setBarberList(barberList);
        return barberListResult;
    }

    @Override
    public Barber findBarber(long barberId) {
        return barberDao.selectBarberById(barberId);
    }

    @Override
    public List<BarberHairstyle> findBarberHairstyleList(long barberId, int pageIndex, int pageSize) {
        return barberHairstyleDao.selectListByBarberId(barberId, pageIndex, pageSize);
    }

    @Override
    public List<BarberHairstyle> findBarberSelfHairstyleList(long barberId, int pageIndex, int pageSize, int status) {
        return barberHairstyleDao.selectBarberSelfHairstyleList(barberId, pageIndex, pageSize, status);
    }

    @Override
    public List<BarberHairstyle> findBarberHairstyleList(List<Long> barberHairstyleIdList) {
        return barberHairstyleDao.selectBarberHairstyleList(barberHairstyleIdList);
    }

    @Override
    public List<Barber> findBarberList(List<Long> barberIdList) {
        return barberDao.selectBarberList(barberIdList);
    }

    @Override
    public BarberHairstyle findBarberHairstyle(long hairstyleId) {
        return barberHairstyleDao.selectById(hairstyleId);
    }

    @Override
    public List<BarberHairstyle> findBarberHairstyleList(int listOrderType, int cityId, int businessCircleId, int gender, double longitude, double latitude, int pageIndex, int pageSize) {
        List<BarberHairstyle> barberHairstyleList;
        if (listOrderType == FilterType.DISTANCE) {
            List<Long> hairstyleIdList = hairstyleLocationDao.findHairstyleNearbyLocation(cityId, businessCircleId, gender, longitude, latitude, pageIndex, pageSize);
            barberHairstyleList = barberHairstyleDao.selectBarberHairstyleList(hairstyleIdList);
        }
        else {
            barberHairstyleList = barberHairstyleDao.selectBarberHairstyleList(listOrderType, cityId, businessCircleId, gender, pageIndex, pageSize);
        }
        return barberHairstyleList;
    }

    @Override
    public List<BarberAppointment> findBarberAppointmentListByDayTime(long barberId, int appointmentDay) {
        return barberAppointmentDao.selectAppointmentListByDayTime(barberId, appointmentDay);
    }

    @Override
    public List<Barber> searchBarberList(String searchText, int pageIndex, int pageSize) {
        return barberDao.searchBarberList(searchText, pageIndex, pageSize);
    }

    @Override
    public List<BarberHairstyle> searchHairstyle(String searchText, int pageIndex, int pageSize) {
        return barberHairstyleDao.searchBarberHairstyleList(searchText, pageIndex, pageSize);
    }

    @Override
    public BarberToken findBarberToken(String accessToken) {
        BarberToken barberToken = null;
        if (!StringUtil.isNullOrEmpty(accessToken)){
            barberToken = barberTokenDao.findBarberToken(accessToken);
        }
        return barberToken;
    }

    @Override
    public void createPhoneSecurityCode(String phoneNumber, String securityCode) {
        phoneSecurityCodeDao.createPhoneSecurityCode(phoneNumber, securityCode);
    }

    @Override
    public boolean verifyPhoneSecurityCode(String phoneNumber, String securityCode) {
        boolean result = false;
        PhoneSecurityCode phoneSecurityCode = phoneSecurityCodeDao.findPhoneSecurityCode(phoneNumber, securityCode);
        if (phoneSecurityCode != null){
            if (System.currentTimeMillis() - phoneSecurityCode.getCreateTime() <= GlobalConfig.PHONE_SECURITY_CODE_EXPIRED){
                result = true;
            }

            phoneSecurityCodeDao.deleteOne(phoneNumber, securityCode);
        }

        return result;
    }

    @Override
    public Barber create(String telNum, String securityCode, String pwd) {
        Barber barber = new Barber();
        barber.setPhoneNumber(telNum);

        barber.setNickName("");
        barber.setRealName(barber.getNickName());
        barber.setIdCardNumber("");
        barber.setGender(GenderType.UNKNOWN);
        barber.setPositionId(0);
        barber.setPhoneNumber(telNum);
        barber.setCityId(0);
        barber.setDistrictId(0);
        barber.setBusinessCircleId(0);
        barber.setShopId(0);
        barber.setMasterShopName("");
        barber.setSlaveShopName("");
        barber.setAddress("");
        barber.setLongitude(BigDecimal.valueOf(0));
        barber.setLatitude(BigDecimal.valueOf(0));
        barber.setAvatar("");
        barber.setHonor(0);
        barber.setOrderCount(0);
        barber.setFavorableCommentCount(0);
        barber.setCommentCount(0);
        barber.setHairCutOriginalPrice(0);
        barber.setHairCutRealPrice(0);
        barber.setHairModelingOriginalPrice(0);
        barber.setHairModelingRealPrice(0);
        barber.setHairCut(false);
        barber.setHairPerm(false);
        barber.setHairDye(false);
        barber.setHairNurse(false);
        barber.setHairModeling(false);
        barber.setCommentScore(0);
        barber.setStatus(BusinessStatusType.NOT_VERIFY);
        barber.setCreateTime(new Date());
        barber.setPhoneType(PhoneType.UNKNOWN);

        String passwordSalt = UUID.randomUUID().toString().substring(0, 7);
        String password = EncryptionUtil.md5(pwd + "-" + passwordSalt);
        barber.setPassword(password);
        barber.setPasswordSalt(passwordSalt);

        barberDao.create(barber);

        return barber;
    }

    @Override
    public boolean isExist(String phoneNumber) {
        return barberDao.isExistPhoneNumber(phoneNumber);
    }

    @Override
    public String createAccessToken(long barberId, int cityId, int status){
        String accessToken = AccessTokenUtil.createBarberAccessToken(barberId);
        barberTokenDao.insertOrUpdateToken(barberId, accessToken, cityId, status);
        return accessToken;
    }

    @Override
    public void changePwd(String phoneNumber, String pwd) {
        String passwordSalt = UUID.randomUUID().toString().substring(0, 7);
        String password = EncryptionUtil.md5(pwd + "-" + passwordSalt);
        barberDao.updatePassword(phoneNumber, password, passwordSalt);
    }

    @Override
    public Barber findBarber(String phoneNumber) {
        return barberDao.selectBarberByPhone(phoneNumber);
    }

    @Override
    public void updateBarberDetail(Barber barber) {
        barberDao.update(barber);
    }

    @Override
    public List<BarberHairstyle> findBarberHairstyleByFavorable(int pageIndex, int pageSize) {
        return barberHairstyleDao.findBarberHairstyleByFavorable(pageIndex, pageSize);
    }

    @Override
    public List<BarberHairstyle> findBarberHairstyleByTime(int pageIndex, int pageSize) {
        return barberHairstyleDao.findBarberHairstyleByTime(pageIndex, pageSize);
    }

    @Override
    public void updateHairstyle(BarberHairstyle barberHairstyle) {
        barberHairstyleDao.update(barberHairstyle);
    }

    @Override
    public void deleteBarberHairstyle(long barberId, long hairstyleId) {
        barberHairstyleDao.deleteBarberHairstyle(barberId, hairstyleId);
    }

    @Override
    public BarberAppointment findBarberAppointment(long barberId, int appointmentDay, int appointmentClock) {
        return barberAppointmentDao.selectAppointmentByDayClockTime(barberId, appointmentDay, appointmentClock);
    }

    @Override
    public void createRestAppointment(long barberId, int appointmentDay, int appointmentClock) {
        BarberAppointment barberAppointment = new BarberAppointment();
        barberAppointment.setBarberId(barberId);
        barberAppointment.setCustomerId(-1);
        barberAppointment.setOrderId(-1);
        barberAppointment.setAppointmentDay(appointmentDay);
        barberAppointment.setAppointmentClock(appointmentClock);
        barberAppointment.setCreateTime(new Date());

        barberAppointmentDao.create(barberAppointment);
    }

    @Override
    public void deleteAppointment(long barberId, int appointmentDay, int appointmentClock) {
        barberAppointmentDao.deleteAppointment(barberId, appointmentDay, appointmentClock);
    }

    @Override
    public List<BarberComment> findBarberCommentList(long barberId, int pageIndex, int pageSize, boolean satisfaction) {
        return barberCommentDao.selectBarberCommentList(barberId, pageIndex, pageSize, satisfaction);
    }

    @Override
    public List<BarberComment> findBarberCommentList(long barberId, int pageIndex, int pageSize) {
        return barberCommentDao.selectBarberCommentList(barberId, pageIndex, pageSize);
    }

    @Override
    public void deleteAppointment(long orderId) {
        barberAppointmentDao.deleteAppointment(orderId);
    }

    @Override
    public void createBarberHairstyle(BarberHairstyle barberHairstyle) {
        barberHairstyleDao.create(barberHairstyle);
    }

    @Override
    public List<Barber> findShopBarberList(long shopId, int businessStatusType) {
        return barberDao.selectShopBarberList(shopId, businessStatusType);
    }

    @Override
    public void updateBarberStatus(long barberId, int businessStatusType) {
        barberDao.updateBarberStatus(barberId, businessStatusType);
    }

    @Override
    public void deleteBarberToken(long barberId) {
        barberTokenDao.delete(barberId);
    }

    @Override
    public void updateBarberHairstyleStatus(long barberId, int status) {
        barberHairstyleDao.updateStatusByBarberId(barberId, status);
    }
}
